﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NetfractionHub.Network;
using NetfractionHub.Network.Protocol.BASE.Factory;

namespace NetfractionHub.RemoteMachine
{
	/// <summary>
	/// The base class for all connections to the hub.
	/// </summary>
	public abstract class Node
	{
		private ClientConnection _connection;
		private Dictionary<string, Network.Protocol.ProtocolFeature> _features;
		private Identity _identity;
		private Security.Identity _securityIdentity;
		private string _sessionId;
		private System.Security.Cryptography.HashAlgorithm _sessionHashAlgorithm;

		protected Node()
		{
			_features = new Dictionary<string, Network.Protocol.ProtocolFeature>();
			_identity = new Identity();
			_identity.NodeType = IdentityNodeTypes.NormalUser;
			_securityIdentity = null;
		}

		public ClientConnection Connection
		{
			get { return _connection; }
			set { _connection = value; }
		}

		/// <summary>
		/// The Session ID used by the hub and clients to uniquely identify other users.
		/// </summary>
		public string SessionId
		{
			get { return _sessionId; }
			set { _sessionId = value; }
		}
		
		/// <summary>
		/// The hashing algorithm negotiated between the Hub and Node when the Node connects.
		/// </summary>
		public virtual System.Security.Cryptography.HashAlgorithm SessionHashAlgorithm
		{
			get { return _sessionHashAlgorithm; }
			set { _sessionHashAlgorithm = value; }
		}

		/// <summary>
		/// Identity information about the node which is intended for clients.
		/// </summary>
		public Identity Identity
		{
			get { return _identity; }
			set { _identity = value; }
		}

		/// <summary>
		/// Identity information about the node for the hub's security subsystem, such as access permissions.
		/// </summary>
		public Security.Identity SecurityIdentity
		{
			get { return _securityIdentity; }
			set { _securityIdentity = value; }
		}

		/// <summary>
		/// The ProtocolFeatures supported by the node.
		/// </summary>
		public Dictionary<string, Network.Protocol.ProtocolFeature> Features
		{
			get { return _features; }
			set { _features = value; }
		}

		/// <summary>
		/// Retrieve a collection of all Identity parameters, suitable for use by the INF factory class, FactoryINF.
		/// </summary>
		/// <returns></returns>
		public Dictionary<int, object> GetIdentityParameters()
		{
			Dictionary<int, object> parameters = new Dictionary<int,object>();
			
			if (!string.IsNullOrEmpty(this._sessionId))
				parameters.Add((int)FactoryINF.ParameterEnum.SessionID, this._sessionId);

			if (_identity.ClientId != string.Empty)
			{
				parameters.Add((int)FactoryINF.ParameterEnum.ClientID, _identity.ClientId);
			}
			if (_identity.Nickname != string.Empty)
			{
				parameters.Add((int)FactoryINF.ParameterEnum.NickOrHubName, _identity.Nickname);
			}
			if (_identity.Email != string.Empty)
			{
				parameters.Add((int)FactoryINF.ParameterEnum.EmailAddress, _identity.Email);
			}
			if (_identity.Description != string.Empty)
			{
				parameters.Add((int)FactoryINF.ParameterEnum.Description, _identity.Description);
			}
			if (_identity.NodeType != IdentityNodeTypes.NormalUser)
			{
				parameters.Add((int)FactoryINF.ParameterEnum.ClientType, (int)_identity.NodeType);
			}
			parameters.Add((int)FactoryINF.ParameterEnum.MaximumUploadSlots, _identity.UploadSlots);
			parameters.Add((int)FactoryINF.ParameterEnum.ShareSize, _identity.ShareSize);
			parameters.Add((int)FactoryINF.ParameterEnum.SharedFilesCount, _identity.SharedFilesCount);
			parameters.Add((int)FactoryINF.ParameterEnum.AutomaticSlotAllocatorSpeedLimit, _identity.AutomaticSlotAllocatorSpeedLimit);
			parameters.Add((int)FactoryINF.ParameterEnum.MinimumUploadConnectionsForAutoSlotAlloc, _identity.MinimumUploadConnectionsForAutoSlotAlloc);
			parameters.Add((int)FactoryINF.ParameterEnum.ClientVersionIdentifier, _identity.ClientVersion);
			parameters.Add((int)FactoryINF.ParameterEnum.MaximumUploadSpeed, _identity.MaximumUploadSpeed);
			parameters.Add((int)FactoryINF.ParameterEnum.MaximumDownloadSpeed, _identity.MaximumDownloadSpeed);
			parameters.Add((int)FactoryINF.ParameterEnum.UserNormalCount, _identity.HubNormalCount);
			parameters.Add((int)FactoryINF.ParameterEnum.UserOperatorCount, _identity.HubOperatorCount);
			parameters.Add((int)FactoryINF.ParameterEnum.UserRegisteredCount, _identity.HubRegisteredCount);
			if (_identity.AwayStatus != IdentityAwayStatus.Online)
			{
				parameters.Add((int)FactoryINF.ParameterEnum.AwayStatus, Convert.ToInt32(_identity.AwayStatus));
			}
			if (_identity.IPv4Address != System.Net.IPAddress.None)
			{
				parameters.Add((int)FactoryINF.ParameterEnum.IPv4_Address, _identity.IPv4Address.ToString());
			}
			if (_identity.Udp4Port > 0)
			{
				parameters.Add((int)FactoryINF.ParameterEnum.UDPv4_Port, _identity.Udp4Port.ToString());
			}
			if (_identity.IPv6Address != System.Net.IPAddress.IPv6None)
			{
				parameters.Add((int)FactoryINF.ParameterEnum.IPv6_Address, _identity.IPv6Address.ToString());
			}
			if (_identity.Udp6Port > 0)
			{
				parameters.Add((int)FactoryINF.ParameterEnum.UDPv6_Port, _identity.Udp6Port.ToString());
			}
			if (_identity.ClientExtendedFeatures.Count > 0)
			{
				parameters.Add((int)FactoryINF.ParameterEnum.SupportedFeatures, string.Join(",", _identity.ClientExtendedFeatures));
			}
			if (_identity.ReferrerUrl != string.Empty)
			{
				parameters.Add((int)FactoryINF.ParameterEnum.RefererURL, _identity.ReferrerUrl);
			}
			return parameters;
		}
	}
}
